#pragma once
#include "Trait.h"
#include "Iterator.h"
namespace mini
{
	namespace command
	{

		/*------------------------------------------------
		fill_n
		-------------------------------------------------*/
		template<typename OutputIterator, typename Size, typename T>
		OutputIterator fill_n(OutputIterator first, Size n, const T& value)
		{
			while (n > 0)
			{
				--n;
				*first = value;
				++first;
			}
			return first;
		}

		/*------------------------------------------------
		swap
		-------------------------------------------------*/
		template<typename T>
		void swap(T&a, T&b)
		{
			T temp(a);
			a = b;
			b = temp;
		}

		/*------------------------------------------------
		advance
		-------------------------------------------------*/
		template<typename InputIterator, typename Distance >
		void __advance(InputIterator& i, Distance n, inputIteratorTag)
		{
			while (n--)
			{
				++i;
			}
		}

		template<typename BidirectionalIterator, typename Distance>
		void __advance(BidirectionalIterator& i, Distance n, bidirectionalIteratorTag)
		{
			if (n > 0)
			{
				while (n--)
				{
					++i;
				}
			}
			else
			{
				while (n++)
				{
					--i;
				}
			}
		}

		template<typename RandomIterator, typename Distance>
		void __advance(RandomIterator& i, Distance n, randomIteratorTag)
		{
			i += n;
		}

		template<typename InputIterator, typename Distance>
		void advance(InputIterator& i, Distance n)
		{
			typedef typename iteratorTrait<InputIterator>::iterator_category iterator_category;
			__advance(i, n, iterator_category());
		}
		/*------------------------------------------------
		distance
		-------------------------------------------------*/
		template<typename InputIterator>
		typename iteratorTrait<InputIterator>::difference_type
			__distance(InputIterator first, InputIterator last, inputIteratorTag)
		{
			typedef typename iteratorTrait<InputIterator>::difference_type difference_type;
			difference_type n = 0;
			while (first != last)
			{
				++first;
				++n;
			}
			return n;
		}

		template< typename RandomIterator>
		typename iteratorTrait<RandomIterator>::difference_type
			__distance(RandomIterator first, RandomIterator last, randomIteratorTag)
		{
			return last - first;
		}

		template<typename InputIterator>
		typename iteratorTrait<InputIterator>::difference_type
			distance(InputIterator first, InputIterator last)
		{
			typedef  typename iteratorTrait<InputIterator>::iterator_category iterator_category;
			return __distance(first, last, iterator_category());
		}

		/*------------------------------------------------
		uninitializedFillN
		-------------------------------------------------*/
		template<typename ForwardIterator, typename Size, typename T>
		ForwardIterator __uninitializedFillNAux(ForwardIterator first, Size n, const T& x, __false_type)
		{
			ForwardIterator oldFirst = first;
			while (n > 0)
			{
				_Construct(first, x);
				++first;
				--n;
			}

			return oldFirst;
		}

		template<typename ForwardIterator, typename Size, typename T>
		ForwardIterator __uninitializedFillNAux(ForwardIterator first, Size n, const T& x, __true_type)
		{
			fill_n(first, n, x);
			return first;
		}

		template<typename ForwardIterator, typename Size, typename T, typename T1>
		ForwardIterator __uninitializedFillN(ForwardIterator first, Size n, const T& x, T1*)
		{
			typedef typename __type_trait<T1>::is_POD_type is_POD_type;
			return __uninitializedFillNAux(first, n, x, is_POD_type());
		}

		template<typename ForwardIterator, typename Size, typename T>
		ForwardIterator uninitializedFillN(ForwardIterator first, Size n, const T& x)
		{
			return __uninitializedFillN(first, n, x, value_type(first));
		}

		//iterator allocateAndFill(size_type n, const T& value )
		//{
		//	
		//}
	}
}